package com.lyl.example.common.config;

import cn.hutool.core.map.MapUtil;
import com.lyl.example.common.exception.BizException;
import com.lyl.example.common.result.Result;
import com.lyl.example.common.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingRequestHeaderException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Mr.Luo
 * @date 2022-07-06 10:10
 * @desc 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 系统异常
     *
     * @param e 异常
     * @return 异常信息
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> onException(Exception e) {
        log.error(ResultCode.SYSTEM_ERROR.getMsg(), e);
        return Result.build(ResultCode.SYSTEM_ERROR, e.getMessage());
    }

    /**
     * 业务异常
     *
     * @param e 异常
     * @return 异常信息
     */
    @ExceptionHandler(BizException.class)
    public Result<Object> onBusinessException(BizException e) {
        log.error(e.getRes().getMsg(), e);
        return Result.build(e.getRes()).setMessage(e.getErrorMsg());
    }

    /**
     * 校验请求参数(请求参数封装成实体类中)
     *
     * @param e 校验请求参数
     * @return 异常信息
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Map<String, String>> onBindException(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach(fieldError ->
                errorMap.put(fieldError.getField(), fieldError.getDefaultMessage())
        );
        return Result.build(ResultCode.ILLEGAL_PARAM, errorMap);
    }

    /**
     * 校验请求参数
     *
     * @param e 异常
     * @return 异常信息
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Map<String, String>> onMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError) ->
                errorMap.put(fieldError.getField(), fieldError.getDefaultMessage())
        );
        return Result.build(ResultCode.ILLEGAL_PARAM, errorMap);
    }

    /**
     * 校验请求参数(请求参数在方法形参列表中)
     *
     * @param e 参数校验异常
     * @return 异常信息
     * errorMap是截取的e.getMessage()中的数据
     * 如果截取报错，可以直接返回 e.getMessage() 错误消息
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Object> onConstraintViolationException(ConstraintViolationException e) {
        Map<String, String> errorMap;
        try {
            String regex = "(, )?" + e.getMessage().substring(0, e.getMessage().indexOf(".")) + ".";
            errorMap = Stream.of(e.getMessage().split(regex))
                    .filter(t -> !Objects.equals(t, ""))
                    .collect(Collectors.toMap(item -> item.substring(0, item.indexOf(":")).trim(), item ->
                            item.substring(item.indexOf(":") + 1).trim()
                    ));
        } catch (Exception ex) {
            return Result.build(ResultCode.ILLEGAL_PARAM, e.getMessage());
        }
        return Result.build(ResultCode.ILLEGAL_PARAM, errorMap);
    }

    /**
     * 缺失请求头异常
     *
     * @param e 异常
     * @return 异常信息
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingRequestHeaderException.class)
    public Result<Map<String, String>> onMissingRequestHeaderException(MissingRequestHeaderException e) {
        String headerName = e.getHeaderName();
        Map<String, String> errMap = MapUtil.builder(headerName, e.getMessage()).build();
        return Result.build(ResultCode.ILLEGAL_PARAM, errMap);
    }

    /**
     * 请求方式不支持
     *
     * @param e 异常
     * @return 异常信息
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<String> onMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("请求方式不支持", e);
        return Result.build(ResultCode.METHOD_NOT_SUPPORT);
    }

}
